package cc.rengu.igas.bsps.core.service.base;

import cc.rengu.igas.bsps.common.constant.BspsAppParamConstant;
import cc.rengu.igas.bsps.common.constant.BspsTreeNodeConstant;
import cc.rengu.igas.bsps.common.enums.*;
import cc.rengu.igas.bsps.core.model.UserSessionInfo;
import cc.rengu.igas.bsps.core.realize.UserPermissionCheckService;
import cc.rengu.igas.bsps.core.realize.impl.UserPermissionCheckServiceImpl;
import cc.rengu.igas.share.core.model.AgentMchntInfo;
import cc.rengu.igas.share.core.model.GroupMchntInfo;
import cc.rengu.igas.share.core.model.MchntInfo;
import cc.rengu.igas.share.core.model.PlatMchntInfo;
import cc.rengu.igas.share.core.realize.MchntService;
import cc.rengu.igas.share.core.realize.impl.MchntServiceImpl;
import cc.rengu.igas.share.core.realize.impl.RiskMonitorServiceImpl;
import cc.rengu.oltp.service.base.BizBaseService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.enums.AcctTypeEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.RiskMonitorInfo;
import cc.rengu.oltp.service.realize.ImageCodeService;
import cc.rengu.oltp.service.realize.RiskMonitorService;
import cc.rengu.oltp.service.realize.impl.ImageCodeServiceImpl;
import cc.rengu.oltp.utility.annotation.BIZ_AFTER;
import cc.rengu.oltp.utility.annotation.BIZ_BEFORE;
import cc.rengu.oltp.utility.annotation.BIZ_PROCESS;
import cc.rengu.oltp.utility.util.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * 管理操作服务基类
 * Created by 王成 on 2018/5/29.
 */
public abstract class ManageService extends BizBaseService {
    @Override
    protected Object beforeBizProcess() throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        /* Step1：查找BIZ_BEFORE的注解*/
        invokeBizAnnoMethod(BIZ_BEFORE.class);

        String txnNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TXN_NUM);
        String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
        String session = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SESSION);
        String userId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.USER_ID);
        String mchntNo = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.MCHNT_NO);
        String channelId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.CHANNEL_ID);
        String bizType = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.BIZ_TYPE);

        /* 登出交易不验session等信息，在业务类中校验 */
        String OprType = xmlTreeUtil.getXmlTreeStringValue(BspsTreeNodeConstant.OPR_TYPE);
        if (NoCheckTxnInfoEnum.T00BS006.getTxnNum().equals(txnNum) && BspsLogInOutOprEnum.LOGOUT.getOprType().equals(OprType)) {
            rglog.info("session为空，但交易为用户登出时，不做校验，在业务类中校验session");
            /* Step5：交易处理前客户化 */
            return bizBeforeCust();
        }

//        /* Step2：检查验签状态 */
//        rglog.info("检查验签状态");
//        String verifySignFlag = xmlTreeUtil.getXmlTreeStringValue(BspsTreeNodeConstant.VERIFY_SIGN_FLAG);
//        rglog.info("验签标识：" + verifySignFlag);
//        if (AppParamConstant.NO.equals(verifySignFlag)) {
//            rglog.error("签名验证失败，交易码:<{}>", txnNum);
//            if (StringUtil.isEmptyOrNull(session)) {
//                rglog.error("session 为null");
//                throw new BizException(RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespCode(), RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespDesc());
//            }
//
//            String sessionObjStr = RedisUtil.onceGet(session);
//            if (sessionObjStr == null) {
//                rglog.error("根据会话标识<{}>获取会话缓存失败", session);
//                throw new BizException(RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespCode(), RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespDesc());
//            }
//
//            UserSessionInfo userSessionInfo = JSON.parseObject(sessionObjStr, UserSessionInfo.class);
//            if (null == userSessionInfo) {
//                rglog.error("根据会话标识<{}>获取会话缓存失败，转为UserSessionInfo失败。", session);
//                throw new BizException(RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespCode(), RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespDesc());
//            }
//
//            throw new BizException(RespCodeEnum.VERIFY_SIGN_ERROR.getRespCode(), RespCodeEnum.VERIFY_SIGN_ERROR.getRespDesc());
//        }
//
//        rglog.info("验签成功");
//        /* Step3:session检查 */
//        rglog.info("校验session");
//        if (!StringUtil.isEmptyOrNull(session)) {
//            rglog.info("session不为空校验");
//            UserPermissionCheckService userService = new UserPermissionCheckServiceImpl();
//            UserSessionInfo userSessionInfo = userService.checkSessionStatus(instId, session);
//            //校验图形验证码
//            if (ImageCodeCheckTxnInfoEnum.checkTxnNo(txnNum)) {
//                String imageAuthCode = xmlTreeUtil.getXmlTreeStringValue("imageAuthCode");
//                rglog.info("图形验证码校验，图形验证码信息：" + imageAuthCode);
//                ImageCodeService imageCodeService = new ImageCodeServiceImpl();
//                boolean imageVerifyFlag = imageCodeService.verifyImageCode(instId, imageAuthCode, userSessionInfo.getImageCode());
//                /* 清空图片验证码验证信息 */
//                userSessionInfo.setImageValidateType(null);
//                userSessionInfo.setImageCode(null);
//                RedisUtil.onceSet(session, JSONObject.toJSONString(userSessionInfo), BspsAppParamConstant.SESSION_EFFECTIVE_TIME);
//                if (!imageVerifyFlag) {
//                    rglog.error("图片验证码校验失败!");
//                    throw new BizException(RespCodeEnum.IMAGE_CODE_VERIFY_ERROR.getRespCode(), RespCodeEnum.IMAGE_CODE_VERIFY_ERROR.getRespDesc());
//                }
//            }
//            rglog.info("校验权限开始");
//            if (AllCheckTxnInfoEnum.checkTxnNum(txnNum)) {
//                rglog.info("交易商户或者拓展经理权限");
//                if (!userService.checkUserPermission(instId, userId, txnNum, channelId)) {
//                    rglog.error("用户权限校验失败", userId + ":" + txnNum);
//                    throw new BizException(RespCodeEnum.USER_NO_AUTHORITY.getRespCode(), RespCodeEnum.USER_NO_AUTHORITY.getRespDesc());
//                }
//            }
//            if (!NoCheckTxnInfoEnum.checkTxnNo(txnNum) && !AllCheckTxnInfoEnum.checkTxnNum(txnNum)) {
//                //检查用户登录状态
//                rglog.info("用户登录状态校验");
//                userSessionInfo = userService.checkUserLoginSessionStatus(instId, session, userId);
//                rglog.info("校验用户交易权限");
//                //检查该用户角色是否有该交易权限
//                if (!userService.checkNormalUserPermission(instId, userId, mchntNo, txnNum, channelId)) {
//                    rglog.error("用户权限校验失败", userId + ":" + txnNum);
//                    throw new BizException(RespCodeEnum.USER_NO_AUTHORITY.getRespCode(), RespCodeEnum.USER_NO_AUTHORITY.getRespDesc());
//                }
//            }
//            rglog.info("解密加密字段信息开始");
//            List<EncryTxnInfoEnum> decodeTxnInfos = EncryTxnInfoEnum.decodeTxnInfo(txnNum);
//            if (!CollectionUtils.isEmpty(decodeTxnInfos)) {
//                rglog.info("userSession信息:" + JSONObject.toJSONString(userSessionInfo));
//                rglog.info("解密Key:" + userSessionInfo.getSensitiveKey());
//                for (EncryTxnInfoEnum encryTxnInfoEnum : decodeTxnInfos) {
//                    String decodeField = encryTxnInfoEnum.getTxnField();
//                    String decodeValue = xmlTreeUtil.getXmlTreeStringValue(decodeField);
//                    if (!StringUtil.isEmptyOrNull(decodeValue)) {
//                        decodeValue = descriptData(userSessionInfo.getSensitiveKey(), decodeValue);
//                        if (!StringUtil.isEmptyOrNull(decodeValue)) {
//                            rglog.info("解密字段：" + decodeField + "解密值：" + decodeValue);
//                            xmlTreeUtil.setXmlTreeStringValue(decodeField, decodeValue);
//                        } else {
//                            rglog.info("解密字段：" + decodeField + "失败");
//                        }
//                    }
//                }
//            }
//            rglog.info("解密加密字段信息结束");
//        }
//        //商户状态校验
//        if (!StringUtils.isEmpty(mchntNo)) {
//            rglog.info("校验商户状态");
//            String mchntType = xmlTreeUtil.getXmlTreeStringValue("mchntType");
//            MchntService mchntService = new MchntServiceImpl();
//            if (BspsMchntTypeEnum.AGENT_MCHNT.getMchntType().equals(mchntType) || mchntNo.startsWith("AG")) {
//                //代理商商户AG
//                AgentMchntInfo agentMchntInfo = mchntService.getAgentMchntInfo(instId, mchntNo);
//                if (null == agentMchntInfo) {
//                    rglog.error("获取代理商户信息失败,mchntNo:<{}>", mchntNo);
//                    throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
//                }
//                xmlTreeUtil.setXmlTreeStringValue("mchntPhone", agentMchntInfo.getContactPhone());
//            } else if (BspsMchntTypeEnum.PLAT_MCHNT.getMchntType().equals(mchntType) || mchntNo.startsWith("PM")) {
//                //平台商户PM
//                PlatMchntInfo platMchntInfo = mchntService.getPlatMchntInfo(instId, mchntNo);
//                if (null == platMchntInfo) {
//                    rglog.error("获取平台商户信息失败,mchntNo:<{}>", mchntNo);
//                    throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
//                }
//                xmlTreeUtil.setXmlTreeStringValue("mchntPhone", platMchntInfo.getContactPhone());
//            } else if (BspsMchntTypeEnum.GROUP_MCHNT.getMchntType().equals(mchntType) || mchntNo.startsWith("55")) {
//                //集团商户55
//                GroupMchntInfo groupMchntInfo = mchntService.getGroupMchntInfo(instId, mchntNo);
//                if (null == groupMchntInfo) {
//                    rglog.error("获取集团商户信息失败,mchntNo:<{}>", mchntNo);
//                    throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
//                }
//                xmlTreeUtil.setXmlTreeStringValue("mchntPhone", groupMchntInfo.getContactPhone());
//            } else if (StringUtil.isEmptyOrNull(mchntType) || "00".equals(mchntType)) {
//                //普通商户
//                MchntInfo mchntInfo = mchntService.getMchntInfo(instId, mchntNo);
//                if (null == mchntInfo) {
//                    rglog.error("获取商户信息失败,mchntNo:<{}>", mchntNo);
//                    throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
//                }
//                xmlTreeUtil.setXmlTreeStringValue("mchntPhone", mchntInfo.getContactPhone());
//                /*校验产品权限*/
//                boolean checkResult = mchntService.checkMchntAuth(instId, mchntNo, null, txnNum, bizType, AcctTypeEnum.ALL.getAcctType());
//                if (!checkResult) {
//                    rglog.error("商户<{}>无此交易<{}>权限!", mchntNo, txnNum);
//                    throw new BizException(RespCodeEnum.MCHNT_NO_PERMISSION.getRespCode(), RespCodeEnum.MCHNT_NO_PERMISSION.getRespDesc());
//                }
//            } else {
//                rglog.error("商户类型信息异常");
//                throw new BizException(RespCodeEnum.ILLEGAL_OPERATION.getRespCode(), RespCodeEnum.ILLEGAL_OPERATION.getRespDesc());
//            }
//            rglog.info("校验商户状态完成");
//        }

        /* Step5：交易处理前客户化 */
        return bizBeforeCust();
    }

    @Override
    protected BizResponse callBizService(Object request) throws Exception {
        /* Step1：公共业务处理 */

        /* Step2：查找BIZ_PROCESS的注解 */
        invokeBizAnnoMethod(BIZ_PROCESS.class);

        /* Step3：业务逻辑处理*/
        return bizProcessCust(request);
    }

    @Override
    protected void afterBizProcess(BizResponse response) throws Exception {
        /* Step1：业务调用后公共处理*/

        /* Step2：查找BIZ_AFTER的注解 */
        invokeBizAnnoMethod(BIZ_AFTER.class);

        /* Step3：业务调用后客户化处理 */
        bizAfterCust(response);
    }

    @Override
    protected RiskMonitorInfo getRiskMonitorInfo() {
        RiskMonitorInfo riskMonitorInfo = new RiskMonitorInfo();
        RiskMonitorService riskMonitorService = new RiskMonitorServiceImpl();
        riskMonitorInfo.setTransMonitor(riskMonitorService);
        return riskMonitorInfo;
    }

    /**
     * 业务处理前客户化处理
     *
     * @return 业务处理实体类
     */
    protected abstract Object bizBeforeCust() throws Exception;

    /**
     * 业务逻辑处理客户化处理
     *
     * @param request 业务处理前的返回实体类
     * @return 业务处理结果
     */
    protected abstract BizResponse bizProcessCust(Object request) throws Exception;

    /**
     * 业务处理后逻辑处理
     *
     * @param response 业务调用响应信息
     */
    protected abstract void bizAfterCust(Object response) throws Exception;

    protected String descriptData(String sensitiveKey, String encData) throws Exception {
        //TODO 目前只支持AES PKCS7-CBC
        String algorithmType = "AES";
        if ("AES".equals(algorithmType)) {
            rglog.info("Key:" + new String(Base64.decodeBase64(sensitiveKey)) + ",dataValue:" + new String(Base64.decodeBase64(encData)));
            String descData = AESUtil.pkcs7CbcDecryptData(Base64.decodeBase64(sensitiveKey), Base64.decodeBase64(encData));
            return descData;
        } else {
            byte[] bEncData = Base64.decodeBase64(encData);
            byte[] descData = new byte[bEncData.length];
            int retCode = SM4Util.sms4(bEncData, bEncData.length, ByteUtil.hexStringToByte(sensitiveKey), descData, 0);
            if (retCode == 0) {
                for (int i = 0; i < descData.length; i++) {
                    if (descData[i] == 0) {
                        return new String(descData, 0, i);
                    }
                }
                return new String(descData);
            }
        }

        return null;
    }

}
